package com.noassertions.services;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Locale;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.util.Version;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;

import com.noassertions.data.DAOInterface;
import com.noassertions.domain.Comment;
import com.noassertions.domain.Fit;
import com.noassertions.domain.Rider;
import com.noassertions.domain.User;

public class LuceneIndexer {

    protected final Log log = LogFactory.getLog(getClass());
	private MessageSource messageSource;
	private final File INDEX_DIR; 
	private DAOInterface dao;

    @Autowired
    public LuceneIndexer(MessageSource messageSource, DAOInterface dao) throws CorruptIndexException, LockObtainFailedException, IOException {
        this.messageSource = messageSource;
        this.dao = dao;
        INDEX_DIR = new File(messageSource.getMessage("luceneIndexDir", null, Locale.getDefault()));
        
        // If lucene index doesn't exist or is empty, build a new one from all objects in DB
        String[] numFiles = INDEX_DIR.list();
        if (!INDEX_DIR.exists() || numFiles.length == 0) {
        	log.info("Unable to locate exisiting Lucne Index. Creating a new one.");
        	//start timer and count

        	long start = System.currentTimeMillis();

        	IndexWriter writer = new IndexWriter(FSDirectory.open(INDEX_DIR), new StandardAnalyzer(Version.LUCENE_CURRENT), true, IndexWriter.MaxFieldLength.LIMITED);
        	writer.optimize();
        	writer.close();

        	ArrayList<Rider> riderList = dao.getAllRiders();
        	log.debug("Adding " + riderList.size() + " riders to the Lucene Index.");
        	for (Rider rider : riderList) {
        		this.indexRider(rider);
        	}

        	ArrayList<Fit> fitList = dao.getAllFits();
        	log.debug("Adding " + fitList.size() + " fits to the Lucene Index.");
        	for (Fit fit : fitList) {
        		this.indexFit(fit);
        	}

        	ArrayList<Comment> commentList = dao.getAllComments();
        	log.debug("Adding " + commentList.size() + " comments to the Lucene Index.");
        	for (Comment comment : commentList) {
        		this.indexComment(comment);
        	}

        	int numDocs = riderList.size() + fitList.size() + commentList.size();
        	long execTime = System.currentTimeMillis() - start;

        	log.info("Indexed " + numDocs + " documents in " + execTime + "ms.");
        }
    }	
    
	public void indexRider(Rider rider) throws CorruptIndexException, IOException
	{
		User user = rider.getUser();

		// Factor this out to a spring bean?
		IndexWriter writer = new IndexWriter(FSDirectory.open(INDEX_DIR), new StandardAnalyzer(Version.LUCENE_CURRENT), false, IndexWriter.MaxFieldLength.LIMITED);
		Document luceneDoc = new Document();
		luceneDoc.add(new Field("firstname", user.getFirstname(), Field.Store.YES, Field.Index.ANALYZED));
		luceneDoc.add(new Field("lastname", user.getLastname(), Field.Store.YES, Field.Index.ANALYZED));
		luceneDoc.add(new Field("ridernotes", rider.getNotes(), Field.Store.YES, Field.Index.ANALYZED));
		luceneDoc.add(new Field("id", Integer.toString(rider.getUserid()), Field.Store.YES, Field.Index.ANALYZED));
		writer.addDocument(luceneDoc);
		writer.optimize();
		writer.close();
	}
	
	public void indexFit(Fit fit) throws CorruptIndexException, IOException
	{
		// Factor this out to a spring bean?
		IndexWriter writer = new IndexWriter(FSDirectory.open(INDEX_DIR), new StandardAnalyzer(Version.LUCENE_CURRENT), false, IndexWriter.MaxFieldLength.LIMITED);
		Document luceneDoc = new Document();
		luceneDoc.add(new Field("fitnotes", fit.getNotes(), Field.Store.YES, Field.Index.ANALYZED));
		luceneDoc.add(new Field("id", Integer.toString(fit.getFitid()), Field.Store.YES, Field.Index.ANALYZED));

		writer.addDocument(luceneDoc);
		writer.optimize();
		writer.close();
	}
	
	public void indexComment(Comment comment) throws CorruptIndexException, IOException
	{
		// Factor this out to a spring bean?
		IndexWriter writer = new IndexWriter(FSDirectory.open(INDEX_DIR), new StandardAnalyzer(Version.LUCENE_CURRENT), false, IndexWriter.MaxFieldLength.LIMITED);
		Document luceneDoc = new Document();
		luceneDoc.add(new Field("id", Integer.toString(comment.getCommentid()), Field.Store.YES, Field.Index.ANALYZED));
		luceneDoc.add(new Field("commenter", comment.getCommenter(), Field.Store.YES, Field.Index.ANALYZED));
		luceneDoc.add(new Field("comment", comment.getComment(), Field.Store.YES, Field.Index.ANALYZED));

		writer.addDocument(luceneDoc);
		writer.optimize();
		writer.close();
	}
}